import * as THREE from "three"

import { BookBase } from "./BookBase"
import type { IBoBoBook } from "src/interfaces/ICBook"
export class BoBook extends BookBase {
  radius: number = 0
  constructor(data: IBoBoBook) {
    const { name, width, height, depth, total, radius } = data
    super(width, height, depth)
    this.radius = radius
    for (let i = 0; i < total; i += 2) {
      const group = new THREE.Group()
      const page = this.createRoundedSquare(
        name,
        width,
        height,
        depth,
        radius,
        i,
        i + 1,
        total / 2
      )
      group.add(page)
      page.position.set(width / 2, height / 2, 0) // 设置每一页的坐标
      // 添加进场景
      // 设置组的位置和名字
      group.position.z = (-(i + 1) * (depth + 0)) / 2 - 12.5
      group.name = `page_${i / 2}`
      // 将group 添加进 数组中
      this.book_group.add(group)
    }
  }

  /**
   * @description:
   * @param {string} book_name: 书本宽度
   * @param {number} width: 书本宽度
   * @param {number} height: 书本高度
   * @param {number} depth: 书本深度
   * @param {number} radius: 书本圆角
   * @param {number} front_num: 正面图案编号
   * @param {number} back_num: 反面图案编号
   * @param {number} page_total: 几张纸
   * @return {*}:
   */
  createRoundedSquare(
    book_name: string,
    width: number,
    height: number,
    depth: number,
    radius: number,
    front_num: number,
    back_num: number,
    page_total: number
  ): THREE.Group {
    const page_group = new THREE.Group()
    const frontShape = this.boo_shape(width, height, radius)
    // 加载正面纹理
    const front_texture = this.loadColorTexture(book_name, `${front_num}`)
    // 加载背面纹理
    const back_texture = this.loadColorTexture(book_name, `${back_num}`)
    // 加载书脊纹理
    const book_back = this.loadColorTexture(
      book_name,
      `bs_0${page_total - front_num / 2}`
    ) // 书脊纹理
    // 创建正面平面
    const frontGeometry = new THREE.ShapeGeometry(frontShape)
    this.generateUVs(frontGeometry) // 为几何体生成UV坐标
    const frontMaterial = new THREE.MeshPhongMaterial({
      map: front_texture,
      side: THREE.FrontSide,
    })

    const frontMesh = new THREE.Mesh(frontGeometry, frontMaterial)
    frontMesh.position.z = depth + 0.1 // 移动到正面位置

    // 创建背面平面
    const backGeometry = new THREE.ShapeGeometry(frontShape)
    this.generateMirroredUVs(backGeometry) // 为几何体生成UV坐标
    back_texture.flipY = false
    const backMaterial = new THREE.MeshPhongMaterial({
      map: back_texture,
      side: THREE.DoubleSide,
    })

    const backMesh = new THREE.Mesh(backGeometry, backMaterial)
    backMesh.position.z = -0.1 // 移动到背面位置
    // 创建书脊
    const book_spine_geometry = new THREE.PlaneGeometry(depth, height)
    const book_spine_material = new THREE.MeshPhongMaterial({
      map: book_back,
      side: THREE.DoubleSide,
    })
    const book_spine_mesh = new THREE.Mesh(
      book_spine_geometry,
      book_spine_material
    )
    book_spine_mesh.position.x = -width / 2 - 0.1 // 移动到背面位置
    book_spine_mesh.position.z = depth / 2
    book_spine_mesh.rotation.y = -Math.PI / 2 // 如果正就是从左往右翻转，实际我们是从右往左翻转

    // 挤出设置
    const extrudeSettings = {
      depth: depth,
      bevelEnabled: false,
      // bevelSegments: 2,
      // bevelSize: 0.05,
      // bevelThickness: 0.05,
    }

    // 书的中间位置
    const sideGeometry = new THREE.ExtrudeGeometry(frontShape, extrudeSettings)
    const sideMaterial = new THREE.MeshPhongMaterial({
      color: 0xeffffff,
      side: THREE.DoubleSide, // 侧面需要双面渲染}
    })
    const sideMesh = new THREE.Mesh(sideGeometry, sideMaterial)

    // 添加到组
    page_group.add(frontMesh)
    page_group.add(backMesh)
    page_group.add(sideMesh)
    page_group.add(book_spine_mesh)

    return page_group
  }

  boo_shape(width: number, height: number, radius: number) {
    // 创建组来包含正面和背面
    const frontShape = new THREE.Shape()
    const size = width // 正方形大小

    // 起始点 - 左下角
    frontShape.moveTo(-size / 2, -size / 2)

    // 底部直线到右下角圆角起点
    frontShape.lineTo(size / 2 - radius, -size / 2)

    // 右下角圆角（使用二次贝塞尔曲线）
    frontShape.quadraticCurveTo(
      size / 2,
      -size / 2, // 控制点
      size / 2,
      -size / 2 + radius // 终点
    )
    // 右侧直线到右上角圆角起点
    frontShape.lineTo(size / 2, size / 2 - radius)
    // 右上角圆角
    frontShape.quadraticCurveTo(
      size / 2,
      size / 2, // 控制点
      size / 2 - radius,
      size / 2 // 终点
    )
    // 顶部直线到左上角
    frontShape.lineTo(-size / 2, size / 2)
    // 左侧直线回到起点
    frontShape.lineTo(-size / 2, -size / 2)

    return frontShape
  }

  // 为ShapeGeometry生成UV坐标的函数
  generateUVs(geometry: THREE.ShapeGeometry) {
    geometry.computeBoundingBox()

    const max = geometry.boundingBox
      ? geometry.boundingBox.max
      : new THREE.Vector3(-0, -0, -0)
    const min = geometry.boundingBox
      ? geometry.boundingBox.min
      : new THREE.Vector3(-0, -0, -0)
    const offset = new THREE.Vector2(0 - min.x, 0 - min.y)
    const range = new THREE.Vector2(max.x - min.x, max.y - min.y)

    const uvAttributes = geometry.getAttribute("uv")
    const positions = geometry.getAttribute("position")
    const count = positions.count

    // 如果没有UV属性，创建一个
    if (!uvAttributes) {
      const uvs = new Float32Array(count * 2)
      geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2))
    }

    // 更新UV坐标
    const uvs = geometry.getAttribute("uv")
    for (let i = 0; i < count; i++) {
      const x = positions.getX(i)
      const y = positions.getY(i)

      // 将顶点坐标映射到UV坐标 (0-1范围)
      const u = (x + offset.x) / range.x
      const v = (y + offset.y) / range.y

      uvs.setXY(i, u, v)
    }

    uvs.needsUpdate = true
  }

  // 镜像UV生成（用于背面）
  generateMirroredUVs(geometry: THREE.ShapeGeometry) {
    geometry.computeBoundingBox()

    const max = geometry.boundingBox
      ? geometry.boundingBox.max
      : new THREE.Vector3(-0, -0, -0)
    const min = geometry.boundingBox
      ? geometry.boundingBox.min
      : new THREE.Vector3(-0, -0, -0)
    const offset = new THREE.Vector2(0 - min.x, 0 - min.y)
    const range = new THREE.Vector2(max.x - min.x, max.y - min.y)

    const positions = geometry.getAttribute("position")
    const count = positions.count

    const uvs = new Float32Array(count * 2)

    for (let i = 0; i < count; i++) {
      const x = positions.getX(i)
      const y = positions.getY(i)

      // 镜像处理：水平翻转UV
      const u = 1 - (x + offset.x) / range.x // 1-u 实现水平镜像
      const v = (y + offset.y) / range.y

      uvs[i * 2] = u
      uvs[i * 2 + 1] = 1 - v
    }

    geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2))
  }
}
